"""
自定义序列化器
"""
from datetime import datetime

from rest_framework import serializers
from rest_framework.fields import empty, ChoiceField
from rest_framework.request import Request
from rest_framework.serializers import ModelSerializer
from django_restql.mixins import DynamicFieldsMixin
from django.utils.translation import gettext_lazy as _
from utils import dispatch


class CustomModelSerializer(DynamicFieldsMixin, ModelSerializer):
    """
    增强DRF的ModelSerializer,可自动更新模型的审计字段记录
    (1)self.request能获取到rest_framework.request.Request对象
    """
    # 创建人的审计字段名称, 默认creator, 继承使用时可自定义覆盖
    creator_field_id = 'creator'
    # 添加默认时间返回格式
    create_time = serializers.DateTimeField(
        format='%Y-%m-%d %H:%M:%S', required=False, read_only=True
    )
    update_time = serializers.DateTimeField(
        format='%Y-%m-%d %H:%M:%S', required=False, read_only=True
    )

    def __init__(self, instance=None, data=empty, request=None, **kwargs):
        super().__init__(instance, data, **kwargs)
        self.request: Request = request or self.context.get('request', None)

    def create(self, validated_data):
        if self.request:
            if str(self.request.user) != 'AnonymousUser':
                if self.creator_field_id in self.fields.fields:
                    validated_data[self.creator_field_id] = self.request.user
        return super().create(validated_data)

    @property
    def errors(self):
        errors = super().errors
        verbose_errors = dict()

        # fields = { field.name: field.verbose_name } for each field in model
        fields = dict()
        for field in self.Meta.model._meta.get_fields():
            if hasattr(field, 'verbose_name'):
                fields[field.name] = field.verbose_name
        # iterate over errors and replace error key with verbose name if exists
        for field_name, error in errors.items():
            if field_name in fields:
                verbose_errors[str(fields[field_name])] = error
            else:
                verbose_errors['错误'] = error
        return verbose_errors


class DictionaryField(ChoiceField):

    default_error_messages = {
        'invalid_choice': _('请选择正确的值')
    }
    html_cutoff = None
    html_cutoff_text = _('More than {count} items...')

    def __init__(self, dict_key, **kwargs):
        self.dick_kv = dispatch.get_dictionary_kv(dict_key)
        super().__init__(list(self.dick_kv.keys()), **kwargs)

    def to_internal_value(self, data):
        if data == '' and self.allow_blank:
            return ''
        try:
            return self.choice_strings_to_values[str(data)]
        except KeyError:
            self.fail('invalid_choice')

    def to_representation(self, value):
        return self.dick_kv.get(value, '')


class ImportCharField(serializers.CharField):
    default_error_messages = {
        # 'required': _('请填写{help_text}'),
        'blank': _('{help_text}不能为空'),
        # 'null': _('{help_text}不能为空')
    }

    def run_validation(self, data=serializers.empty):
        # Test for the empty string here so that it does not get validated,
        # and so that subclasses do not need to handle it explicitly
        # inside the `to_internal_value()` method.
        if data == '' or (self.trim_whitespace and str(data).strip() == ''):
            if not self.allow_blank:
                self.fail('blank', help_text=self.help_text)
            return ''
        return super().run_validation(data)


class ImportDateField(serializers.DateField):
    default_error_messages = {
        'date': _('{help_text}格式错误'),
    }

    def to_internal_value(self, value):
        if not value:
            return None
        try:
            return datetime.strptime(value, '%Y-%m-%d').date()
        except ValueError:
            self.fail('date', help_text=self.help_text)


class ImportDictionaryField(ChoiceField):
    default_error_messages = {
        'invalid_choice': _('请选择正确的{help_text}')
    }
    html_cutoff = None
    html_cutoff_text = _('More than {count} items...')

    def __init__(self, dict_key, **kwargs):
        self.dick_kv = dispatch.get_dictionary_kv(dict_key)
        super().__init__(list(self.dick_kv.keys()), **kwargs)

    def to_internal_value(self, data):
        if data == '' and self.allow_blank:
            return ''
        for k, v in self.dick_kv.items():
            if v == data:
                return k
        self.fail('invalid_choice', help_text=self.help_text)

